package utils

import (
	"math"

	"github.com/prometheus/common/log"
)

type XY struct {
	x, y float64
}

func NewXY(x, y float64) XY { return XY{x, y} }

type Stder interface {
	Len() int
	X(int) float64
}

type DX []XY
type DY []XY

func (d DX) Len() int        { return len(d) }
func (d DY) Len() int        { return len(d) }
func (d DX) X(i int) float64 { return d[i].x }
func (d DY) X(i int) float64 { return d[i].y }

func Stdev(d Stder) (mean, std float64) {
	l := d.Len()
	if l == 0 {
		return
	}
	if l == 1 {
		mean = d.X(0)
		return
	}
	sx, sxx := 0.0, 0.0
	for i := 0; i < l; i++ {
		x := d.X(i)
		sx += x
		sxx += x * x
	}
	mean = sx / float64(l)
	std = sxx - sx*sx/float64(l)
	std /= float64(l - 1)
	std = math.Sqrt(std)
	return
}

func Xcorr(xy []XY, mx, my float64) float64 {
	sxy := 0.0
	for _, v := range xy {
		sxy += (v.x - mx) * (v.y - my)
	}
	return sxy
}

func Axb(xy []XY) (a, b, my, sy float64) {
	mx, sx := Stdev(DX(xy))
	my, _ = Stdev(DY(xy))
	sxy := Xcorr(xy, mx, my)
	a = sxy / (sx * sx) / float64(len(xy)-1)
	b = my - a*mx
	sy = 0
	for i := range xy {
		e := DY(xy).X(i) - a*DX(xy).X(i)
		sy += e * e
	}
	log.Info("timing:", sy)
	for i := range xy {
		log.Info(i, DY(xy).X(i), DX(xy).X(i))
	}
	return
}
